<template>
  <div class="table-view">
    <div class="table-view-wrapper">
      <!--搜索条件-->
      <template v-if="searchFormPosition === 'top'">
        <ElCollapseTransition>
          <div v-if="toolbarProps.searchable" v-show="isSearchVisible" class="search-form-top">
            <ElForm
              ref="form"
              label-position="right"
              :model="searchModel || searchPanelProps.model"
              size="mini"
              :label-width="labelWidth"
              @submit.native.prevent.capture="onSearchClick">
              <FormItemConfigProvider reactive>
                <ElRow :gutter="0">
                  <slot name="search-form">
                    <p>请添加搜索条件！</p>
                  </slot>
                  <FormItem style="float: right">
                    <ElButton type="primary" native-type="submit" size="mini">开始搜索</ElButton>
                    <ElButton size="mini" style="margin-left: 10px" @click="onClearClick">清除条件</ElButton>
                  </FormItem>
                </ElRow>
              </FormItemConfigProvider>
            </ElForm>
          </div>
        </ElCollapseTransition>
      </template>
      <!--顶部工具条-->
      <Toolbar
        v-bind="toolbarProps"
        refreshable
        @search="toggleSearch"
        @settings="() => $refs.table.toggleSettings()"
        @del="del"
        @create="create"
        @reload="reloadTableAndTree"
        @imp="importDialogVisible = true"
        v-on="toolbarListeners">
        <template #default>
          <slot name="toolbar-button" :selected-rows="selectedRows"></slot>
        </template>
        <template #toolbar-left>
          <slot name="toolbar-left" :selected-rows="selectedRows"></slot>
        </template>
        <template #toolbar-right>
          <slot name="toolbar-right" :del="del" :create="create" :reload="reloadTableAndTree" :selected-rows="selectedRows"></slot>
        </template>
        <template v-for="item in buttonSlots" #[item]>
          <slot :name="item" :selected-rows="selectedRows"></slot>
        </template>
      </Toolbar>
      <div class="table-view-content-wrapper">
        <div class="table-view-content">
          <!--侧栏-->
          <div v-if="treeProps.show" ref="treeScroller" class="table-view-sidebar" @scroll="onTreeScroll">
            <div style="font-size: 16px">视图导航</div>
            <EditableTree ref="tree" v-bind="treeProps" readonly v-on="treeListeners">
              <template #default="{ node, data }">
                <slot name="tree-node" :node="node" :data="data">
                  <span>
                    <i
                      :class="node.childNodes.length > 0 ? (node.expanded ? 'el-icon-folder-opened' : 'el-icon-folder') : 'el-icon-tickets'"
                      class="node-icon"></i>
                    <slot name="tree-label" :node="node" :data="data">{{ node.label }}</slot>
                  </span>
                </slot>
              </template>
            </EditableTree>
          </div>
          <!--表格-->
          <div class="table-view-table">
            <PageableTable
              ref="table"
              :border="border"
              :class="[
                {
                  'border-top': borderTop,
                  'border-bottom': borderBottom,
                  'border-left': borderLeft || (treeAttrs && treeAttrs.show),
                  'border-right': borderRight
                }
              ]"
              v-bind="tableProps"
              v-on="tableListeners"
              @row-dblclick="rowDbClick"
              @selection-change="onSelectionChange">
              <slot name="columns"></slot>
            </PageableTable>
          </div>
        </div>
        <!--搜索条件-->
        <template v-if="searchFormPosition === 'right'">
          <Transition name="slide">
            <div v-if="toolbarProps.searchable" v-show="isSearchVisible" :style="{ width: `${searchPanelProps.width}px` }" class="slide-panel">
              <!--<div class="slide-panel-line">
                <div class="slide-panel-line-indicator"></div>
              </div>-->
              <div class="slide-panel-content">
                <ElForm
                  ref="form"
                  label-position="right"
                  :model="searchModel || searchPanelProps.model"
                  size="mini"
                  :label-width="labelWidth"
                  @submit.native.prevent.capture="onSearchClick">
                  <FormItemConfigProvider block :wrap-col="false">
                    <ElRow :gutter="0">
                      <slot name="search-form">
                        <p>请添加搜索条件！</p>
                      </slot>
                    </ElRow>
                  </FormItemConfigProvider>
                  <ElFormItem label-width="0">
                    <div class="slide-panel-actions">
                      <ElButton type="primary" native-type="submit" size="mini">开始搜索</ElButton>
                      <ElButton size="mini" @click="onClearClick">清除条件</ElButton>
                    </div>
                  </ElFormItem>
                </ElForm>
              </div>
            </div>
          </Transition>
        </template>
      </div>
      <slot></slot>
    </div>
  </div>
</template>

<script>
  import { hasOwn, isArray, isFunction, isString, toStringArray, trace, warning } from '@web-utils/core'
  import { merge } from '@web-utils/integrations/lodash'
  import { fillPath } from '@/util'
  import FormItemConfigProvider from '@/components/form/FormItemConfigProvider'
  import { processButtons } from '@/util/auth'

  const builtInButtons = [
    'back',
    'create',
    'save',
    'withdraw',
    'edit',
    'submit',
    'publish',
    'agree',
    'disagree',
    'reject',
    'finish',
    'cancel',
    'enable',
    'exp',
    'imp',
    'del',
    'disabled',
    'reload',
    'slot'
  ]

  export default {
    name: 'TableView',
    bus: {
      reloadTableView(viewId) {
        if (!this._viewIds) {
          return
        }
        if (isString(viewId) || isArray(viewId)) {
          let viewIds = viewId
          if (isString(viewIds)) {
            viewIds = viewIds.split(',')
          }

          if (this._viewIds.some(value => viewIds.includes(value))) {
            trace.call(this.$parent || {}, 'reloadTree')
            this.reloadTable()
          }
        } else {
          warning.call(this.$parent || {}, '`viewId`的类型必须是字符串或数组')
        }
      },
      reloadTreeView(viewId) {
        if (!this._viewIds) {
          return
        }
        if (isString(viewId) || isArray(viewId)) {
          let viewIds = viewId
          if (isString(viewIds)) {
            viewIds = viewIds.split(',')
          }

          if (this._viewIds.some(value => viewIds.includes(value))) {
            if (this.$refs.tree) {
              trace.call(this.$parent || {}, 'reloadTreeView')
              this.reloadTree()
            }
          }
        } else {
          warning.call(this.$parent || {}, '`viewId`的类型必须是字符串或数组')
        }
      }
    },
    components: { FormItemConfigProvider },
    props: {
      viewId: String,
      searchPanelAttrs: {
        type: Object,
        default: () => {}
      },
      toolbarAttrs: {
        type: Object,
        default: () => {}
      },
      toolbarListeners: Object,
      treeAttrs: {
        type: Object,
        default: () => {}
      },
      treeListeners: Object,
      tableAttrs: Object,
      searchModel: Object,
      tableListeners: {
        type: Object,
        default: () => {}
      },
      deleteApi: Function,
      borderTop: Boolean,
      borderBottom: Boolean,
      borderLeft: Boolean,
      borderRight: Boolean,
      border: {
        type: Boolean,
        default: true
      },
      labelWidth: {
        type: String,
        default: '80px'
      },
      formPath: [String, Function],
      searchFormPosition: {
        type: String,
        default: 'top'
      }
    },
    data() {
      return {
        importDialogVisible: false,
        selectedRows: [],
        isSearchVisible: false
      }
    },
    computed: {
      buttonSlots() {
        return builtInButtons.filter(value => this.$scopedSlots[value])
      },
      toolbarProps() {
        const defaultProps = {}
        const toolbarAttrs = merge({}, this.toolbarAttrs, defaultProps)
        let buttons = toolbarAttrs?.buttons || this.$parent.buttons
        buttons = buttons || []
        // if (!buttons.includes('reload')) {
        //   buttons = [...buttons, 'reload']
        // }
        // toolbarAttrs.buttons = buttons.filter(value => value !== 'back')
        toolbarAttrs.buttons = buttons

        toolbarAttrs.buttons = processButtons(toolbarAttrs.buttons)

        toolbarAttrs.buttons = toStringArray(toolbarAttrs.buttons)
        toolbarAttrs.searchable = !!this.$scopedSlots['search-form']?.()
        return toolbarAttrs
      },
      treeProps() {
        const defaultProps = {
          treeProps: {
            children: 'children',
            label: 'label',
            isLeaf: data => {
              if (hasOwn(data, 'hasChildren')) {
                return !data.hasChildren
              } else if (hasOwn(data, 'hasChild')) {
                return !data.hasChild
              } else {
                return true
              }
            }
          },
          show: false,
          lazy: true,
          readonly: true,
          data: [],
          'expand-first-node': false,
          'default-expand-all': false
        }
        return merge({}, this.treeAttrs, defaultProps)
      },
      tableProps() {
        const api = this.tableAttrs.api || this.$parent.getPage
        const defaultProps = {
          model: this.searchModel || {},
          height: 'auto',
          'highlight-current-row': true,
          api
        }
        return merge({}, this.tableAttrs, defaultProps)
      },
      searchPanelProps() {
        const defaultProps = {
          width: 350,
          model: this.searchModel || {}
        }
        return merge({}, this.searchPanelAttrs, defaultProps)
      }
    },
    created() {
      this._viewIds = []
      if (this.viewId) {
        this._viewIds.push(this.viewId)
      }
      if (!this._viewIds.includes(this.$parent.$options.name)) {
        this._viewIds.push(this.$parent.$options.name)
      }
    },
    async activated() {
      if (this.$refs.treeScroller) {
        if (this.treeScrollTop) {
          this.$refs.treeScroller.scrollTop = this.treeScrollTop
        }
        if (this.treeScrollLeft) {
          this.$refs.treeScroller.scrollLeft = this.treeScrollLeft
        }
      }
    },
    methods: {
      onTreeScroll() {
        this.treeScrollTop = this.$refs.treeScroller.scrollTop
        this.treeScrollLeft = this.$refs.treeScroller.scrollLeft
      },
      toggleSearch() {
        this.isSearchVisible = !this.isSearchVisible
      },
      async onSearchClick() {
        await this.reloadTable()
      },
      async onClearClick() {
        this.$emit('reset')
        this.$refs.form.resetFields()
        await this.reloadTable()
      },
      openFrom(row) {
        this.$router.push(fillPath(this.formPath, row))
      },
      rowDbClick(row) {
        if (!this.tableListeners?.['row-dblclick'] && this.formPath) {
          this.openFrom(row)
        }
      },
      onSelectionChange(rows) {
        this.selectedRows = rows
      },
      create() {
        if (!this.toolbarListeners?.create && this.formPath) {
          this.openFrom()
        }
      },
      async del() {
        const api = this.deleteApi || this.$parent.del
        if (!this.toolbarListeners?.del && isFunction(api)) {
          if (!this.selectedRows.length) {
            this.$message.warning('请选择要删除的记录！')
            return
          }
          await this.$confirm(`您确定要删除选中的[<span class="break-word" style="color: orange">${this.selectedRows.length}</span>]行记录吗？`, '系统提示', {
            type: 'warning',
            modal: true,
            dangerouslyUseHTMLString: true,
            closeOnClickModal: false,
            beforeClose: async (action, instance, done) => {
              if (action === 'confirm') {
                try {
                  instance.confirmButtonLoading = true
                  instance.confirmButtonText = '删除...'
                  const res = await api.call(
                    this,
                    this.selectedRows.map(value => value.id)
                  )
                  this.$message.success(res.data.msg || '删除成功')
                  await this.reloadTableAndTree()
                  // TODO 优化待办刷新逻辑
                  await this.$refreshHome('WorkToDoList')
                  await this.$refreshWork()
                } catch (_) {}
              }
              done()
            }
          }).catch(_ => _)
        }
      },
      reloadTable() {
        this.$refs.table?.reload()
      },
      async refreshTable() {
        await this.$refs.table?.getPage()
      },
      reloadTree() {
        this.$refs.tree?.reloadTree()
      },
      reloadTableAndTree() {
        this.reloadTable()
        this.reloadTree()
      },
      currentRow() {
        return this.$refs.table.currentRow
      },
      getPageQuery() {
        return this.$refs.table.getPageQuery()
      }
    }
  }
</script>

<style lang="scss">
  .table-view {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 10px;

    $border: 1px solid #ebeef5;

    .toolbar {
      height: 46px;
      line-height: 46px;
      border-bottom: none;
    }

    .table-view-wrapper {
      @include flex-column;
      height: 100%;
      overflow: hidden;
      border-radius: 4px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

      .pageable-table-wrapper {
        padding-right: 10px;
      }

      .el-pagination {
        padding: 6px 10px;
        color: #303133;
        font-weight: 700;
        white-space: nowrap;
        text-align: left;
      }
    }

    // .el-table--border {
    //   border: none;
    // }
    .border-top {
      .el-table--border {
        border-top: $border;
      }
    }

    .border-bottom {
      .el-table--border {
        border-bottom: $border;
      }
    }

    .border-left {
      .el-table--border,
      .el-pagination {
        border-left: $border;
      }
    }

    .border-right {
      .el-table--border {
        border-right: $border;
      }
    }

    .table-view-content-wrapper {
      position: relative;
      flex: 1;
      overflow: hidden;
    }

    .table-view-content {
      position: absolute;
      top: 0;
      left: 0;
      display: flex;
      width: 100%;
      height: 100%;
      background-color: white;
    }

    .table-view-sidebar {
      @include flex-not-shrink;
      width: 240px;
      height: 100%;
      padding: 10px;
      overflow: auto;

      .et-tree-wrapper {
        display: table;
        overflow: visible;
      }
    }

    .table-view-table {
      @include flex-item;
      height: 100%;
    }

    .search-form-top {
      padding: 10px 10px 0;
      background-color: #fff;
    }

    .slide-panel {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      z-index: 5;
      display: flex;
      background-color: white;
      box-shadow: 0 0 10px 5px rgba(0, 0, 0, 0.1);

      .slide-panel-line {
        @include flex-not-shrink;
        position: relative;
        width: 3px;
        height: 100%;
        background-color: #ddd;
      }

      .slide-panel-line-indicator {
        position: absolute;
        top: 50%;
        left: 0;
        width: 100%;
        height: 50px;
        background-color: #aaa;
        transform: translateY(-50%);
      }

      .slide-panel-actions {
        display: flex;
        align-items: center;
        justify-content: center;
        margin-top: 10px;
      }

      .slide-panel-content {
        flex: 1;
        padding: 10px;
        overflow: auto;

        .el-date-editor {
          width: 100%;
        }
      }
    }
  }
</style>
